﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace DomSharp.ExpressionVisitors
{
    internal class DomExpressionVisitor : ExpressionVisitor
    {
        Stack<string> codeStack = new Stack<string>();
        [return: NotNullIfNotNull("node")]
        public string Translate(Expression node)
        {
            base.Visit(node);
            return string.Join(".", codeStack);
        }
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var visitor = new DomMethodCallExpressionVisitor();
            visitor.Visit(node);
            codeStack.Push(visitor.VisitResult);
            return node;
        }

        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (node.Type == typeof(string))
            {
                codeStack.Push($@"""{node.Value?.ToString()}""");
            }
            else if (node.Type == typeof(DateTime) || node.Type == typeof(DateTime?) || node.Type == typeof(DateTimeOffset) || node.Type == typeof(DateTimeOffset?))
            {
                codeStack.Push($@"""{node.Value?.ToString()}""");
            }
            else if (node.Type == typeof(IntOrString) || node.Type == typeof(IntOrString?))
            {
                var intOrString = node.Value as IntOrString?;
                if (intOrString.HasValue)
                {
                    if (intOrString.Value.IsString)
                    {
                        codeStack.Push($@"""{intOrString.Value.String}""");
                    }
                    else
                    {
                        codeStack.Push($@"""{intOrString.Value.Int}px""");
                    }
                }
            }
            else if (node.Type.IsValueType || node.Type.IsPrimitive)
            {
                codeStack.Push(node.Value?.ToString().ToLower());
            }
            else if (node.Type == typeof(HtmlElement))
            {
                var id = (node.Value as HtmlElement).ElementReference.Id;
                codeStack.Push($@"document.getElementById(""{id}"")");
            }
            return base.VisitConstant(node);
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            codeStack.Push(node.Member.Name[0].ToString().ToLower() + node.Member.Name.Substring(1));
            return base.VisitMember(node);
        }

        protected override Expression VisitBinary(BinaryExpression node)
        {
            var leftVisitor = new DomExpressionVisitor();
            var left = leftVisitor.Translate(node.Left);
            var rightVisitor = new DomExpressionVisitor();
            var right = rightVisitor.Translate(node.Right);
            switch (node.NodeType)
            {
                case ExpressionType.Assign:
                    codeStack.Push($"{left} = {right}");
                    break;
            }
            return node;
        }
    }
}
